import { HttpClient } from '@angular/common/http';
import { ComponentFactoryResolver, Injectable, Injector } from '@angular/core';
import { BuilderHTMLElement, FarrisDesignBaseComponent } from '@farris/designer-element';
import {
  ComponentBindingSourceContext, ComponentResolveContext, DesignerHostSettingService,
  DesignViewModelField, DesignViewModelService, DgControl,
  DomService, FormBinding, FormBindingType, FormVariable, SchemaService
} from '@farris/designer-services';
import { IdService } from '@farris/ui-common';
import { BsModalService } from '@farris/ui-modal';
import { NotifyService } from '@farris/ui-notify';
import { merge } from 'lodash-es';
import { Observable, of, Subject } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { ComponentBuildInfo, InnerComponentCreatorComponent } from '../components/inner-component-creator';
import { ComponentCreatorService } from '../components/inner-component-creator/component-creator.service';
import { BindingEditorComponent } from '../property-editor/binding-editor/binding-editor.component';

/**
 * 表单拖拽服务类
 */
@Injectable({
  providedIn: 'root'
})
export class DragResolveService {

  constructor(
    public domService: DomService,
    public designViewModelService: DesignViewModelService,
    private componentFactoryResolver: ComponentFactoryResolver,
    private modalService: BsModalService,
    public injector: Injector,
    public notifyService: NotifyService,
    public schemaService: SchemaService,
    public designerHostSettingServ: DesignerHostSettingService,
    public http: HttpClient
  ) { }

  /**
   * 获取拖拽上下文信息
   * @param sourceEl 拖拽源HTML节点
   * @param targetComponentInstance 目标组件实例
   */
  public getComponentResolveContext(sourceEl: BuilderHTMLElement, targetComponentInstance: FarrisDesignBaseComponent)
    : ComponentResolveContext {

    const resolveContext = new ComponentResolveContext();

    resolveContext.sourceType = sourceEl.getAttribute('data-sourceType') || 'move' as any;
    resolveContext.controlType = sourceEl.getAttribute('data-controlType');
    resolveContext.controlTypeName = sourceEl.getAttribute('data-controlTypeName');
    resolveContext.controlCategory = sourceEl.getAttribute('data-category');
    resolveContext.defaultFieldType = sourceEl.getAttribute('data-fieldType');
    resolveContext.defaultUdtId = sourceEl.getAttribute('data-udtId');
    resolveContext.bindingTargetId = sourceEl.getAttribute('data-fieldId');
    resolveContext.useStrictMappingRule = sourceEl.getAttribute('data-useStrictMappingRule') === 'true';
    resolveContext.controlFeature = sourceEl.getAttribute('data-feature');
    resolveContext.controlTemplate = {
      templateId: sourceEl.getAttribute('data-templateId'),
      templateCategory: sourceEl.getAttribute('data-templateCategory'),
    };

    resolveContext.parentComponentInstance = targetComponentInstance;
    if (resolveContext.controlCategory === 'input') {
      resolveContext.bindingType = 'field';
    } else if (resolveContext.controlCategory === 'dataCollection') {
      resolveContext.bindingType = 'entity';
    }

    // 现有控件移动位置：从控件实例上获取控件类型
    if (sourceEl.componentInstance) {
      resolveContext.controlType = sourceEl.componentInstance.type;
      resolveContext.controlCategory = sourceEl.componentInstance.category;

    }

    if (targetComponentInstance) {
      resolveContext.bindingTargetInSidebar = DgControl.Sidebar && targetComponentInstance.type === DgControl.Sidebar.type;
    }
    return resolveContext;
  }


  /**
   * 根据拖拽元素解析并创建控件
   * @param sourceEl 源Element
   * @param targetComponentInstance 目标控件的实例
   */
  public resolveComponentCreationContextByDrop(sourceEl: BuilderHTMLElement, targetComponentInstance: FarrisDesignBaseComponent): Observable<ComponentResolveContext> {

    const componentResolveContext = this.getComponentResolveContext(sourceEl, targetComponentInstance);

    return this.resolveBindingSource(componentResolveContext).pipe(
      switchMap((bindingSourceContext: ComponentBindingSourceContext) => {
        // 若返回undefined 代表终止后续生成。返回null不会终止
        if (bindingSourceContext === undefined) {
          return of(null);
        } else {
          componentResolveContext.bindingSourceContext = bindingSourceContext;
          this.resolveComponentSchema(componentResolveContext);
          return of(componentResolveContext);
        }

      })
    );
  }
  /**
   * 解析拖拽元素，并根据场景展示不同的绑定窗口
   * @param componentResolveContext 拖拽上下文
   */
  public resolveBindingSource(componentResolveContext: ComponentResolveContext): Observable<ComponentBindingSourceContext> {
    const { bindingType } = componentResolveContext;

    if (componentResolveContext.controlCategory === 'input') {
      // 输入类，触发展示字段绑定窗口
      return this.triggerBindingField(componentResolveContext);
    } else if (bindingType === 'entity') {
      // 实体类，触发展示实体绑定窗口
      return this.triggerBindingEntity(componentResolveContext);
    } else {
      // 容器类，不需要绑定信息，直接生成控件DOM结构即可
      return of(null);
    }

  }
  /**
   * 字段绑定
   * @param componentResolveContext 拖拽上下文
   */
  public triggerBindingField(componentResolveContext: ComponentResolveContext): Observable<ComponentBindingSourceContext> {
    if (componentResolveContext.bindingTargetId) {
      // 包含字段标识，说明是实体树拖拽字段
      return this.getBindingSourceContextBySchemaTree(componentResolveContext);
    } else {
      // 工具箱拖拽控件
      return this.getBindingSourceContextByControlBox(componentResolveContext);
    }

  }

  /**
   * 实体树节点拖拽生成控件：解析字段的绑定信息
   * @param componentResolveContext 拖拽上下文
   */
  private getBindingSourceContextBySchemaTree(componentResolveContext: ComponentResolveContext): Observable<ComponentBindingSourceContext> {
    const { bindingTargetId, parentComponentInstance } = componentResolveContext;

    const displayedFieldsMap = this.getDisplayedFieldsMapBySelectedEntity(componentResolveContext);
    if (displayedFieldsMap.has(bindingTargetId)) {
      this.notifyService.warning('表单已经包含此字段，请勿重复添加');
      // 结束
      return of(undefined);
    } else {
      const resolveResult = this.schemaService.getFieldByIDAndVMID(bindingTargetId, parentComponentInstance.viewModelId);
      const componentBindingSourceContext: ComponentBindingSourceContext = { bindingType: 'field' };


      // 注意，这里复制一下，否则是跟表单dom使用的同一个json对象，在上面添加的属性会保存到表单dom上。
      const schemaField = merge({}, resolveResult.schemaField);

      componentBindingSourceContext.entityFieldNode = schemaField;

      // 若添加到分组内，需要保存向vm保存groupId和groupName
      const { groupId, groupName } = this.getFieldGroupInfo(parentComponentInstance);
      componentBindingSourceContext.designViewModelField = merge({}, schemaField, { groupId, groupName });

      return of(componentBindingSourceContext);

    }
  }
  /**
   * 控件工具箱拖拽生成控件，创建字段绑定模态框
   */
  protected getBindingSourceContextByControlBox(componentResolveContext: ComponentResolveContext): Observable<ComponentBindingSourceContext> {
    const { controlType, parentComponentInstance, useStrictMappingRule } = componentResolveContext;
    //  列表支持的控件类型有限
    if (parentComponentInstance.type === 'DataGrid' || parentComponentInstance.type === 'TreeGrid') {
      const notAllowedType = [
        DgControl.CheckGroup.type, DgControl.RadioGroup.type, DgControl.RichTextBox.type,
        DgControl.Image.type, DgControl.Tags.type, DgControl.Avatar.type, DgControl.ImageUpload.type];
      if (notAllowedType.includes(controlType)) {
        this.notifyService.warning('列表暂不支持此控件，请重新选择');
        // 结束
        return of(undefined);
      }
    }
    const bindingSourceResult = new Subject<ComponentBindingSourceContext>();

    const componentBindingSourceContext: ComponentBindingSourceContext = { bindingType: 'field' };


    const editorComponentFactory = this.componentFactoryResolver.resolveComponentFactory(BindingEditorComponent);
    const editorComponentFactoryRef = editorComponentFactory.create(this.injector);

    editorComponentFactoryRef.instance.editorParams.viewModelId = parentComponentInstance.viewModelId;
    editorComponentFactoryRef.instance.unusedOnly = true;
    editorComponentFactoryRef.instance.bindingControlType = controlType;
    editorComponentFactoryRef.instance.useStrictMappingRule = useStrictMappingRule

    // 限制绑定类型
    editorComponentFactoryRef.instance.editorParams.allowedBindingType = [DgControl.Form.type, DgControl.FieldSet.type, 'TableTd', DgControl.ResponseLayoutItem.type].includes(parentComponentInstance.type) ? null : 'Form';

    const fieldSelectorDialog = this.modalService.show(editorComponentFactoryRef, {
      title: '绑定',
      width: 900,
      height: 500,
      showButtons: true,
      buttons: editorComponentFactoryRef.instance.modalFooter
    });

    editorComponentFactoryRef.instance.closeModal.subscribe(() => {
      fieldSelectorDialog.close();
      // 结束
      bindingSourceResult.next(undefined);
    });

    editorComponentFactoryRef.instance.submitModal.subscribe((data: { value: FormBinding, parameters: any }) => {
      fieldSelectorDialog.close();
      if (!data || !data.value) {
        return;
      }
      // 若添加到分组内，需要向vm保存groupId和groupName
      const { groupId, groupName } = this.getFieldGroupInfo(parentComponentInstance);

      if (data.value.type === 'Form') {
        // 绑定字段
        const entityField = data.parameters.selectedData as DesignViewModelField;
        componentBindingSourceContext.entityFieldNode = entityField;

        componentBindingSourceContext.designViewModelField = merge({}, entityField, { groupId, groupName });

        bindingSourceResult.next(componentBindingSourceContext);
      } else {
        // 绑定变量
        const varibleField = data.parameters.selectedData as FormVariable;
        componentBindingSourceContext.variableFieldNode = merge({}, varibleField, { groupId, groupName });
        bindingSourceResult.next(componentBindingSourceContext);

      }
    });
    return bindingSourceResult;
  }
  /**
   * 生成控件schema结构
   * @param componentResolveContext 拖拽上下文
   */
  public resolveComponentSchema(componentResolveContext: ComponentResolveContext) {
    const { controlCategory, controlType, bindingSourceContext } = componentResolveContext;

    // 存储新建的控件dom结构，由designer-view统一追加到DOM结构中
    let domElement = null;
    if (componentResolveContext.componentInstance) {
      return;
    }
    switch (controlCategory) {
      case 'input': {
        if (bindingSourceContext && bindingSourceContext.entityFieldNode) {
          domElement = this.resolveControlSchemaByEntityField(componentResolveContext);

        } else if (bindingSourceContext && bindingSourceContext.variableFieldNode) {
          domElement = this.resolveControlSchemaByVariableField(componentResolveContext);
        }
        break;
      }
      case 'dataCollection': {
        if (bindingSourceContext && bindingSourceContext.bindingType === 'entity') {
          domElement = this.resolveComponentSchemaByEntity(componentResolveContext);
        }
        break;
      }
      default: {

        domElement = this.designerHostSettingServ.controlService.getControlMetaData(controlType, true, componentResolveContext.parentComponentInstance, componentResolveContext.controlFeature);

        this.resolveProcessInstanceForApproval(domElement, controlType);

        // 唯一化id
        const radomNum = Math.random().toString().slice(2, 6);
        const typePrefix = controlType.toLowerCase();
        if (domElement.type === controlType) {
          domElement.id = `${typePrefix}_${radomNum}`;
        }
      }
    }

    if (domElement) {
      componentResolveContext.componentSchema = domElement;
    }
  }

  /**
   * 根据实体字段创建控件
   * @param componentResolveContext 上下文
   */
  public resolveControlSchemaByEntityField(componentResolveContext: ComponentResolveContext) {
    const { controlType, bindingSourceContext, parentComponentInstance } = componentResolveContext;

    const viewModelId = parentComponentInstance.viewModelId;
    const controlCreatorService = this.designerHostSettingServ.controlCreatorService;
    const bindingTarget = bindingSourceContext.entityFieldNode;

    let domElement;
    // 如果目标父容器是列表，这里不是创建输入控件而是grid列
    if (parentComponentInstance.type === 'DataGrid' || parentComponentInstance.type === 'TreeGrid') {
      domElement = controlCreatorService.createGridFieldBySchemaFeild(bindingTarget, bindingTarget.bindingPath,
        parentComponentInstance.component.fieldEditable, DgControl.GridField.type, 'Farris', controlType);

      // 因为列表比较特殊，不走统一的容器类添加逻辑，这里单独将新建列添加到grid中
      parentComponentInstance.component.fields.push(domElement);

    } else {
      // 创建输入类控件
      const formComponent = this.domService.getComponentByVMId(viewModelId);
      const formComponentTypeName = formComponent ? formComponent.componentType : 'form-col-4';

      domElement = controlCreatorService.createControlBySchemaFeild(
        bindingTarget, formComponentTypeName, controlType, parentComponentInstance.componentId);
    }

    // 同步viewModel Fields：因为在绑定编辑器里已经添加到dgViewModel了，但是没有分组信息，所以这里先删除，再重新添加
    const dgViewModel = this.designViewModelService.getDgViewModel(viewModelId);
    dgViewModel.removeField([bindingSourceContext.entityFieldNode.id]);
    dgViewModel.addField(bindingSourceContext.designViewModelField);
    if (controlType) {
      dgViewModel.changeField(bindingSourceContext.entityFieldNode.id, { editor: { $type: controlType } });
    }

    return domElement;
  }
  /**
   * 根据变量创建控件（变量只能创建卡片区域的控件，不支持DataGrid）
   * @param componentResolveContext 上下文
   */
  private resolveControlSchemaByVariableField(componentResolveContext: ComponentResolveContext) {
    const { controlType, bindingSourceContext, parentComponentInstance } = componentResolveContext;
    const viewModelId = parentComponentInstance.viewModelId;

    const controlCreatorService = this.designerHostSettingServ.controlCreatorService;
    const bindingTarget = bindingSourceContext.variableFieldNode;

    const formComponent = this.domService.getComponentByVMId(viewModelId);
    const formComponentTypeName = formComponent ? formComponent.componentType : 'form-col-4';

    const domElement = controlCreatorService.createControlByVariable(
      bindingTarget, formComponentTypeName, controlType, parentComponentInstance.componentId);

    const viewModelField = {
      type: FormBindingType.Variable,
      id: bindingTarget.id,
      fieldName: bindingTarget.code,
      groupId: bindingTarget.groupId || '',
      groupName: bindingTarget.groupName || ''
    };
    this.domService.deleteViewModelFieldById(viewModelId, bindingTarget.id);
    this.domService.addViewModelField(viewModelId, viewModelField);

    return domElement;
  }
  /**
   * 根据实体创建组件
   * @param componentResolveContext 上下文
   */
  public resolveComponentSchemaByEntity(componentResolveContext: ComponentResolveContext) {
    const { bindingSourceContext, parentComponentInstance } = componentResolveContext;

    const componentNode = bindingSourceContext.componentNode;
    const componentRefNode = bindingSourceContext.componentRefNode;
    const viewModelNode = bindingSourceContext.viewModelNode;
    const parentContainer = this.domService.domDgMap.get(parentComponentInstance.id);
    if (!parentContainer.contents) {
      parentContainer.contents = [];
    }
    // 插入component和viewmodel节点
    this.domService.addViewModel(viewModelNode);
    this.domService.addComponent(componentNode);

    // 将子组件追加到options中
    if (parentComponentInstance.options && parentComponentInstance.options.childComponents) {
      parentComponentInstance.options.childComponents.push(componentNode);
    }

    // 父容器增加新增 删除按钮
    this.appendAddDeleteBtnToParentContainer(componentResolveContext);

    this.designViewModelService.assembleDesignViewModel();

    return componentRefNode;
  }

  /**
   * 触发展示实体绑定窗口
   * @param componentResolveContext 拖拽上下文
   */
  public triggerBindingEntity(componentResolveContext: ComponentResolveContext): Observable<ComponentBindingSourceContext> {
    const bindingSourceResult = new Subject<ComponentBindingSourceContext>();

    const { bindingTargetId, allowedEntityLevel, controlType, needExcludeDisplayedFields, bindingTargetInSidebar } = componentResolveContext;

    const componentBindingSourceContext: ComponentBindingSourceContext = { bindingType: 'entity' };
    const editorComponentFactory = this.componentFactoryResolver.resolveComponentFactory(InnerComponentCreatorComponent);
    const editorComponentFactoryRef = editorComponentFactory.create(this.injector);
    editorComponentFactoryRef.instance.componentType = controlType;
    editorComponentFactoryRef.instance.fixedEntityId = bindingTargetId;
    editorComponentFactoryRef.instance.allowedEntityLevel = allowedEntityLevel;
    editorComponentFactoryRef.instance.needExcludeDisplayedFields = needExcludeDisplayedFields;
    editorComponentFactoryRef.instance.bindingTargetInSidebar = bindingTargetInSidebar;

    const modalConfig = {
      title: '添加组件',
      width: 800,
      height: 530,
      showButtons: true,
      showMaxButton: true,
      buttons: editorComponentFactoryRef.instance.btns
    };
    switch (controlType) {
      case 'FileUploadPreview': {
        modalConfig.title = '添加附件';
        modalConfig.width = 520;
        modalConfig.height = 340;
        modalConfig.showMaxButton = false;
        editorComponentFactoryRef.instance.needExcludeDisplayedEntity = true;
        break;
      }
      case 'ListView': {
        modalConfig.title = '添加列表';
        modalConfig.width = 520;
        modalConfig.height = 340;
        modalConfig.showMaxButton = false;
        break;
      }
      case 'DataGrid': {
        modalConfig.title = '添加表格';
        break;
      }
      case 'Form': {
        modalConfig.title = '添加卡片';
        break;
      }
      default: {
        if (controlType && controlType.startsWith('form-col-')) {
          modalConfig.title = '添加卡片';
        }
      }

    }

    const entitySelectorDialog = this.modalService.show(editorComponentFactoryRef, modalConfig);
    editorComponentFactoryRef.instance.cancel.subscribe(() => {
      entitySelectorDialog.close();
      // 结束
      bindingSourceResult.next(undefined);
    });
    editorComponentFactoryRef.instance.save.subscribe((buildInfo: ComponentBuildInfo) => {
      entitySelectorDialog.close();

      buildInfo.parentContainerType = componentResolveContext.parentComponentInstance && componentResolveContext.parentComponentInstance.type;
      const componentBindingResult = this.resolveComponentBuildInfo(buildInfo);
      componentBindingSourceContext.componentNode = componentBindingResult.componentNode;
      componentBindingSourceContext.componentRefNode = componentBindingResult.componentRefNode;
      componentBindingSourceContext.viewModelNode = componentBindingResult.viewModelNode;
      bindingSourceResult.next(componentBindingSourceContext);
    });

    return bindingSourceResult;
  }

  /**
   * 组装Component、ViewModel ComponentRef结构
   * @param buildInfo 组件构造信息
   */
  public resolveComponentBuildInfo(buildInfo: ComponentBuildInfo): {
    viewModelNode: any;
    componentNode: any;
    componentRefNode: any;
  } {

    const componentCreatorService = new ComponentCreatorService(this.designerHostSettingServ, this.domService);
    const componentRefNode = componentCreatorService.createComponentRefNode(buildInfo);

    const componentNode = componentCreatorService.createComponentNode(buildInfo);

    const viewModelNode = componentCreatorService.createViewModeNode(buildInfo);

    return { viewModelNode, componentNode, componentRefNode };
  }

  /**
   * 获取控件拖拽后的分组信息，以便于后续记录到视图模型
   * @param parentComponentInstance 拖拽目标组件的实例
   */
  public getFieldGroupInfo(parentComponentInstance: FarrisDesignBaseComponent) {
    let groupId: string;
    let groupName: string;
    if (parentComponentInstance.type === DgControl.FieldSet.type) {
      groupId = parentComponentInstance.component.id;
      groupName = parentComponentInstance.component.title;
    }
    return { groupId, groupName };
  }

  /**
   * 拖拽DataGrid：父容器追加新增、删除按钮
   * @param componentResolveContext
   */
  public appendAddDeleteBtnToParentContainer(componentResolveContext: ComponentResolveContext, parentComponentSchema?: any) {
    const { bindingSourceContext, parentComponentInstance, controlType, sourceType } = componentResolveContext;
    const { componentNode, viewModelNode } = bindingSourceContext;

    if (!parentComponentSchema && parentComponentInstance) {
      parentComponentSchema = parentComponentInstance.component;
    }

    // 限制父容器为Tab或Section
    if (!parentComponentSchema || ![DgControl.Tab.type, DgControl.TabPage.type, DgControl.Section.type].includes(parentComponentSchema.type)) {
      return;
    }
    // 限制子表
    if (viewModelNode.bindTo === '/') {
      return;
    }
    // 限制列表或卡片
    if (componentNode.componentType !== 'dataGrid' && !componentNode.componentType.includes('form-')) {
      return;
    }
    // 获取新增删除子表命令可用的控制器id。
    const cardControllerId = this.getAddRemoveCommandBelongedControllerId();
    if (!cardControllerId) {
      return;
    }
    // 1、父容器添加新增删除按钮
    const vmPrefix = viewModelNode.id.replace(/-/g, '').replace(/_/g, '');
    const btnType = [DgControl.Tab.type, DgControl.TabPage.type].includes(parentComponentSchema.type) ? 'TabToolbarItem' : 'SectionToolbarItem';
    const btns = [{
      id: `${componentNode.id}-button-add`,
      type: btnType,
      title: '新增',
      disable: "!viewModel.stateMachine['canAddDetail']",
      appearance: {
        class: 'btn btn-secondary f-btn-ml'
      },
      visible: true,
      click: `root-viewModel.${viewModelNode.id}.${vmPrefix}AddItem1`
    },
    {
      id: `${componentNode.id}-button-remove`,
      type: btnType,
      title: '删除',
      disable: "!viewModel.stateMachine['canRemoveDetail']",
      appearance: {
        class: "btn btn-secondary f-btn-ml"
      },
      visible: true,
      click: `root-viewModel.${viewModelNode.id}.${vmPrefix}RemoveItem1`
    }];
    // let parentComponentSchema = parentComponentInstance.component;
    if (parentComponentInstance.type === DgControl.Tab.type && parentComponentSchema && parentComponentSchema.contents && parentComponentSchema.contents.length) {
      parentComponentSchema = parentComponentSchema.contents.find(tabPage => tabPage.id === parentComponentInstance.selectedTabPageId);
    }
    if (!parentComponentSchema) {
      return;
    }
    if (!parentComponentSchema.toolbar) {
      parentComponentSchema.toolbar = {
        type: [DgControl.Tab.type, DgControl.TabPage.type].includes(parentComponentSchema.type) ? 'TabToolbar' : 'SectionToolbar',
        id: `${parentComponentSchema.id}_toolbar`,
        position: 'inHead',
        contents: []
      };
    }
    if (!parentComponentSchema.toolbar.contents) {
      parentComponentSchema.toolbar.contents = [];
    }
    parentComponentSchema.toolbar.contents = parentComponentSchema.toolbar.contents.concat(btns);

    // 2、视图模型增加新增删除命令
    const idService = this.injector.get(IdService);
    const addCommandId = idService.generate();
    const deleteCommandId = idService.generate();
    viewModelNode.commands.push(
      {
        id: addCommandId,
        code: `${vmPrefix}AddItem1`,
        name: '增加一条子表数据1',
        params: [],
        handlerName: 'AddItem',
        cmpId: cardControllerId,
        shortcut: {},
        extensions: []
      },
      {
        id: deleteCommandId,
        code: `${vmPrefix}RemoveItem1`,
        name: '删除一条子表数据1',
        params: [
          {
            name: 'id',
            shownName: '待删除子表数据的标识',
            value: `{DATA~/#{${componentNode.id}}${viewModelNode.bindTo}/id}`
          }
        ],
        handlerName: 'RemoveItem',
        cmpId: cardControllerId,
        shortcut: {},
        extensions: []
      }
    );


    // 3、记录构件命令
    const webCmds = this.domService.getWebCmds();
    let cardCmd = webCmds.find(webCmd => webCmd.id === cardControllerId);
    if (!cardCmd) {
      cardCmd = {
        id: cardControllerId,
        path: '/projects/packages/Inspur.GS.Gsp.Web.WebCmp/webcmd',
        name: 'CardController.webcmd',
        refedHandlers: []
      };
      webCmds.push(cardCmd);
    }

    cardCmd.refedHandlers.push(
      {
        host: addCommandId,
        handler: 'AddItem'
      },
      {
        host: deleteCommandId,
        handler: 'RemoveItem'
      }
    );
  }

  /**
   * 获取新增删除子表命令可用的控制器id。
   */
  private getAddRemoveCommandBelongedControllerId(): string {
    const webCmds = this.domService.getWebCmds();
    // 卡片控制器 / 树卡控制器 / 高级列卡控制器
    const optionalControllerId = [
      '8172a979-2c80-4637-ace7-b13074d3f393',
      '8fe977a1-2b32-4f0f-a6b3-2657c4d03574',
      '45be24f9-c1f7-44f7-b447-fe2ada458a61'
    ];
    const availableController = webCmds.find(cmd => optionalControllerId.includes(cmd.id));

    if (availableController) {
      return availableController.id;
    }
  }

  private getDisplayedFieldsMapBySelectedEntity(componentResolveContext: ComponentResolveContext) {
    const displayedFieldsMap = new Map<string, boolean>();
    const { bindingTargetId, parentComponentInstance } = componentResolveContext;
    const targetViewModel = this.domService.getViewModelById(parentComponentInstance.viewModelId);
    const targetEntityInfo = this.schemaService.getTableInfoByViewModelId(targetViewModel.id);
    const targetComponent = this.domService.getComponentByVMId(targetViewModel.id);
    if (!targetEntityInfo || !targetComponent) {
      return displayedFieldsMap;
    }
    /** 当前组件是否在侧边栏中 */
    const targetComponentInSidebar = this.checkComponentIfInSidebar(targetComponent.id);

    // 根组件和table组件内的输入控件与form内不能重复
    let targetCmpType = targetComponent.componentType;
    if (targetCmpType === 'Frame' || targetCmpType === 'table' || (targetCmpType && targetCmpType.startsWith('form'))) {
      targetCmpType = 'form';
    }
    this.domService.viewmodels.forEach(viewModel => {
      if (!viewModel.fields || viewModel.fields.length === 0) {
        return;
      }
      const componentNode = this.domService.getComponentByVMId(viewModel.id);
      const entityInfo = this.schemaService.getTableInfoByViewModelId(viewModel.id);
      let sourceCmpType = componentNode.componentType;
      if (sourceCmpType === 'Frame' || sourceCmpType === 'table' || (sourceCmpType && sourceCmpType.startsWith('form'))) {
        sourceCmpType = 'form';
      }
      // 绑定同一个实体，并且是同类型的组件（form类、dataGrid类...）
      if (sourceCmpType !== targetCmpType || entityInfo.id !== targetEntityInfo.id) {
        return;
      }
      /** 组件是否在侧边栏中 */
      const componentInSidebar = this.checkComponentIfInSidebar(componentNode.id);

      // 若当前组件在侧边栏中，那么只收集同样在侧边栏中的字段。
      if (targetComponentInSidebar && componentInSidebar) {
        viewModel.fields.forEach(field => {
          displayedFieldsMap.set(field.id, true);
        });
      }

      // 若当前组件不在侧边栏中，那么只收集不在侧边栏中的字段
      if (!targetComponentInSidebar && !componentInSidebar) {
        viewModel.fields.forEach(field => {
          displayedFieldsMap.set(field.id, true);
        });

      }

    });

    return displayedFieldsMap;
  }

  /**
   * 检查卡片组件是否在侧边栏中，在侧边栏中的字段可以与非侧边栏中的字段重复。
   */
  private checkComponentIfInSidebar(cmpNodeId: string) {

    const sidebar = this.domService.selectNode(this.domService.components[0],
      item => DgControl.Sidebar && item.type === DgControl.Sidebar.type && item.contents && item.contents.length &&
        item.contents.find(child => child.type === DgControl.ComponentRef.type && child.component === cmpNodeId));
    if (sidebar) {
      return true;
    }
    return false;
  }

  /**
   * 审批意见、审批记录控件，需要绑定流程实例
   * @param domElement 
   * @param controlType 
   */
  private resolveProcessInstanceForApproval(domElement: any, controlType: string) {
    if (controlType.includes('Approval') && domElement.contents && domElement.contents.length) {

      let approvalField = this.schemaService.getSchemaField('bindingPath', 'processInstance.processInstance');
      if (approvalField) {
        Object.assign(domElement.contents[0], {
          binding: {
            type: 'Form',
            field: approvalField.id,
            path: 'processInstance',
          },
          path: 'processInstance.processInstance',
        });
      }

    }
  }
}
